package controller;

import java.util.ArrayList;

import model.Extra;
import model.Linie;
import model.Schritt;
import model.Spieler;
import model.Spielfeld;

public class Logik {
	public void onCollideLinie(Spieler spieler) {
		spieler.setTot(true);
		this.onSpielerTot(spieler);
	}

	public Schritt onCollideWall(Spieler spieler, float x, float y) {
		if (x < 0) {
			x += Spiel.GAME_WIDTH;
		} else if (x > Spiel.GAME_WIDTH) {
			x -= Spiel.GAME_WIDTH;
		}
		if (y < 0) {
			y += Spiel.GAME_HEIGHT;
		} else if (y > Spiel.GAME_HEIGHT) {
			y -= Spiel.GAME_HEIGHT;
		}

		Linie l = spieler.getLinie();
		return Schritt.createJumpSchritt(l.lastSchritt, x, y);
	}

	public void onSpielerTot(Spieler spieler) {
		for (Spieler s : Spiel.CURRENT_SPIEL.getSpieler()) {
			if (!s.isTot()) {
				s.setPunkte(s.getPunkte() + 1);
				s.getLinie().transform.pointWinner.setValue(1);
			}
		}
		if (isRundeZuEnde())
			onRundeZuEnde();
	}

	public void spielerNachLinks(Spieler spieler) {
		spieler.setLeftPressed(true);
	}

	public void spielerNachRechts(Spieler spieler) {
		spieler.setRightPressed(true);
	}

	public void spielerStopptNachLinks(Spieler spieler) {
		spieler.setLeftPressed(false);
	}

	public void spielerStopptNachRechts(Spieler spieler) {
		spieler.setRightPressed(false);
	}

	public void prepareStep() {
		synchronized (Spiel.CURRENT_SPIEL.extras) {
			if (Math.random() <= 1.0 / 180) {
				Extra e = Extra.getRandomExtra();
				e.x = this.getRandomInX(20);
				e.y = this.getRandomInY(20);
				Spiel.CURRENT_SPIEL.extras.add(e);
			}
			for (Extra e : Spiel.CURRENT_SPIEL.extras) {
				if (e.active)
					continue;

				for (Spieler s : Spiel.CURRENT_SPIEL.getSpieler()) {
					Linie l = s.getLinie();
					if ((e.x - l.getX()) * (e.x - l.getX()) + (e.y - l.getY())
							* (e.y - l.getY()) <= e.radius * e.radius) {
						e.doRunFirst(s);
						break;
					}
				}
			}
		}
		applyExtras();
	}

	public int getRandomInX(int d) {
		return (int) (Math.random() * (Spiel.GAME_WIDTH - 2 * d) + d);
	}

	public int getRandomInY(int d) {
		return (int) (Math.random() * (Spiel.GAME_HEIGHT - 2 * d) + d);
	}

	public void applyExtras() {
		synchronized (Spiel.CURRENT_SPIEL.extras) {
			for (Spieler s : Spiel.CURRENT_SPIEL.getSpieler()) {
				s.getLinie().transform.reset();
			}
			for (int i = Spiel.CURRENT_SPIEL.extras.size() - 1; i >= 0; i--) {
				Extra e = Spiel.CURRENT_SPIEL.extras.get(i);
				if (e.active) {
					e.lifetime--;
					if (e.lifetime == 0) {
						e.die();
						Spiel.CURRENT_SPIEL.extras.remove(e);
					} else
						e.run();
				}
			}
			for (Spieler s : Spiel.CURRENT_SPIEL.getSpieler()) {
				s.getLinie().transform.apply();
			}
		}
	}

	public void moveSpieler(Spielfeld spielfeld, Spieler spieler) {
		Linie l = spieler.getLinie();

		if (spieler.isTot())
			return;

		if (spieler.isLeftPressed())
			l.turnLeft();
		if (spieler.isRightPressed())
			l.turnRight();

		float width = l.width * l.transform.widthFaktor.getValue();
		boolean paint = true;
		float lueckeLength = 3f + width / 2 * l.transform.vFaktor.getValue();
		if (l.lueckeStart + lueckeLength > Spiel.CURRENT_SPIEL.getTime()
				|| l.transform.luecke) {
			paint = false;
		} else if (Math.random() <= (Spiel.CURRENT_SPIEL.getTime() - (l.lueckeStart + lueckeLength)) / 700.0 * l.transform.vFaktor.getValue()) {
			l.startLuecke();
			paint = false;
		}

		Schritt schritt = Schritt.createSchritt(l.lastSchritt, l.phi, l.v
				* l.transform.vFaktor.getValue(), width,
				paint ? spieler.getFarbe() : Schritt.LUECKE_COLOR);

		if (schritt != l.lastSchritt) {
			schritt.setIgnoreSchritt(l.lastSchritt);
		}

		if (spielfeld.collides(schritt)) {
			this.onCollideLinie(spieler);
		} else if (spielfeld.isOutOfFeld(schritt)) {
			schritt = this.onCollideWall(spieler, schritt.getFinalX(),
					schritt.getFinalY());
		}
		synchronized (spielfeld) {
			if (schritt != l.lastSchritt)
				spielfeld.addMove(schritt);
		}
		l.lastSchritt = schritt;
	}

	public boolean isRundeZuEnde() {
		return getLebendigeSpieler() <= 1;
	}

	public int getLebendigeSpieler() {
		int anzahlLebende = 0;
		Spieler[] spieler = Spiel.CURRENT_SPIEL.getSpieler();
		for (Spieler s : spieler) {
			if (!s.isTot())
				anzahlLebende += 1;
		}
		return anzahlLebende;
	}

	void onRundeZuEnde() {
		Spiel.CURRENT_SPIEL.stopRunde();
		Spiel.CURRENT_SPIEL.setAwaitRunde(true);
	}

	public void verteileSpieler(Spielfeld feld, Spieler[] spieler) {
		Spiel.CURRENT_SPIEL.extras = new ArrayList<Extra>();
		for (int i = 0; i < spieler.length; i++) {
			Spieler s = spieler[i];
			Linie l = s.getLinie();

			float delta;
			do {
				l.lastSchritt = Schritt.createJumpSchritt(null,
						getRandomInX(100), getRandomInY(100));

				// Testen, ob die neue Position in Ordnung ist
				delta = 100;
				for (int j = 0; j < i; j++) {
					Linie l2 = spieler[j].getLinie();
					delta = (float) Math.min(
							delta,
							Math.sqrt((l2.getX() - l.getX())
									* (l2.getX() - l.getX())
									+ (l2.getY() - l.getY())
									* (l2.getY() - l.getY())));
				}
			} while (delta < 100);

			l.phi = (float) (Math.random() * 2 * Math.PI);
			l.width = 4;
			l.transform.reset(true);
			l.v = 5;

			synchronized (feld) {
				feld.addMove(l.lastSchritt);
				feld.addMove(Schritt.createSchritt(l.lastSchritt, l.phi, -20,
						l.width, s.getFarbe()));
			}

			l.lueckeStart = 0;
			s.setTot(false);
		}
	}

	public boolean isKonecHry() {
		return false;
	}
}
